package app.framework.security.csrf;

import app.framework.constant.FrontConstants;
import app.framework.constant.FrameworkErrorConstants;
import app.framework.constant.FrameworkMsgConstants;
import app.framework.front.util.WebUtil;
import jasmine.framework.common.util.I18nUtil;
import jasmine.framework.common.util.JsonUtil;
import jasmine.framework.common.util.StringUtil;
import jasmine.framework.web.entity.WebResult;
import jasmine.security.util.SecurityContextUtil;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * <p>
 * 检查 CSRF 令牌，防止跨域攻击。
 * </p>
 *
 * @author mh.z
 */
public class CsrfInterceptor implements HandlerInterceptor {
    private static final String AUTHORIZATION_HEADER = "Authorization";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 不检查通过 OAuth2 登录的用户
        if (StringUtil.isNotEmpty(request.getHeader(AUTHORIZATION_HEADER))) {
            return true;
        }

        // 只检查已登录的用户
        if (!isCurrentUserAuthenticated()) {
            return true;
        }

        // 检查 CSRF 令牌是否匹配
        boolean csrfTokenCheckResult = CsrfTokenUtil.checkCsrfToken(request);

        if (!csrfTokenCheckResult) {
            // 设置响应体信息
            WebUtil.setResponseInfo(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                    FrontConstants.RESPONSE_CONTENT_TYPE_JSON);

            WebResult result = WebResult.error(FrameworkErrorConstants.WRONG_CSRF_TOKEN,
                    I18nUtil.getMessage(FrameworkMsgConstants.WRONG_CSRF_TOKEN));
            String json = JsonUtil.toJson(result);
            // 写入数据到响应体
            WebUtil.writeAndFlush(response, json);

            return false;
        }

        return true;
    }

    /**
     * 判断当前用户是否已登录
     *
     * @return
     */
    protected boolean isCurrentUserAuthenticated() {
        Authentication authentication = SecurityContextUtil.getCurrentAuthentication();

        if ((authentication != null) && !(authentication instanceof AnonymousAuthenticationToken)) {
            return true;
        }

        return false;
    }

}
